#ifndef TRANSFORMERCONTENTQUERYTARGET_HPP_3
#define TRANSFORMERCONTENTQUERYTARGET_HPP_3

#include "logger.hpp"
#include "transContentDefine.h"
#include "transContentErrorCode.h"
#include "transContentDispatcher.hpp"
#include "transContentThreads.hpp"
#include "transContentIDispatcherResponse.hpp"
#include "transContentIRemove.hpp"

class TransContentFuncCallQueryTarget: public transContentIDispResponse, public transContentIRemove{
	private:
		int timeout;
		int localPort;
		int queryCondType;
		int queryValueLen;
		int canBeRemoved;
		int operationResult;
		NodeAddr target;
		char queryCondValue[MAX_DEVICEID_LEN];
		queryTargetCallback qtcb;
		deviceInfo resultInfo;
		pthread_mutex_t waitMutex;
		pthread_cond_t waitCond;

	public:
		TransContentFuncCallQueryTarget(): timeout(INT_MAX), localPort(0), queryCondType(QUERY_DEVICE_COND_IMEI), queryValueLen(0), canBeRemoved(0), operationResult(0), qtcb(NULL), waitMutex(PTHREAD_MUTEX_INITIALIZER), waitCond(PTHREAD_MUTEX_INITIALIZER){
		}
		virtual ~TransContentFuncCallQueryTarget(){
			debug_enter();
			TransContentThreadPool::removeTask(this);
			debug_leave();
		}

		void setTimeout(int timeout){
			this->timeout = timeout;
		}
		int getTimeout(){
			return this->timeout;
		}

		int getOperationResult(){
			return operationResult;
		}

		void setTarget(const NodeAddr* target){
			this->target = *target;
		}

		NodeAddr getTarget(){
			return this->target;
		}

		int canRemoved() const {
			return canBeRemoved;
		}

		void setLocalPort(int port){
			this->localPort = port;
		}
		int getLocalPort(){
			return this->localPort;
		}

		void setQueryValue(int type, void* value, int len){
			memset(queryCondValue, 0x00, MAX_DEVICEID_LEN);
			memcpy(queryCondValue, value, len);
			queryValueLen = len;
			queryCondType = type;
		}
		int getQueryCondType(int* type, void* value, int len){
			*type = queryCondType;
			memcpy(value, queryCondValue, queryValueLen);
			return queryValueLen;	   
		}

		void setFinishedCallback(queryTargetCallback qtcb){
			this->qtcb = qtcb;
		}
		queryTargetCallback getFinishedCallback(){
			return this->qtcb;
		}

		int query(deviceInfo* dInfo);
		int response(char* content, int index);
	private:
		void* finshCallbackRoutem(void* p);
		void queryFinish();
		void finshCallbackIns();

	private:
		///////////////////////////////////////////////////////////////////////////////////////////
		/// query device info packet out:
		///  name | length | mainCode| subCode | localPort | targetDevice | queryCondType | queryCondValueLen | queryCondValue | 
		/// length|    2   |    1    |    1    |     4     |    8         |       1       |       1           |     valuelen   |
		/// offset|    0   |    2    |    3    |     4     |    8         |        16     |       17          |     18         |
		///
		/// query devcie response packet, the start the same as query info packet out, the first is 16+v, not 18, because of first two bytes are length
		///  name | result |showMe| nickLen |  nick  | dIdLen |   dId   |  imei   | ttl    |
		/// lenth |   1    |   1  |   1     |   xx   |   1    |    xx   |    16   |  1     |
		/// offset|  16+v  | 17+v |   18+v  |  19+v  | 19+v+n | 20+v+n  | 20+v+n+d|36+v+n+d| 

		static void setPacketLength(char* buffer, int length){
			*((short*)(buffer)) = (short)length;
		}

		static int getPacketLength(const char* buffer){
			return *((short*)(buffer));
		}

		static void setPacketMainMessage(char* buffer, int code){
			buffer[2] = (char)code;
		}

		static int getPacketMainMessage(const char* buffer, int towards){
			return towards==DUMP_PROTOCOL_PACKET_IN ? buffer[0] : buffer[2];
		}

		static void setPacketSubMessageCode(char* buffer, int code){
			buffer[3] = (char)code;
		}

		static int getPacketSubMessageCode(const char* buffer, int towards){
			return towards==DUMP_PROTOCOL_PACKET_IN ? buffer[1] : buffer[3];
		}

		static void setPacketLocalPort(char* buffer, int port){
			*((int*)(buffer+4)) = port;
		}

		static int getPacketLocalPort(const char* buffer, int towards){
			return towards==DUMP_PROTOCOL_PACKET_IN ? *((int*)(buffer+2)) : *((int*)(buffer+4));
		}

		static void setPacketTarget(char* buffer, const NodeAddr* target){
			*((long long*)(buffer+8)) = target->serial_id;
		}

		static NodeAddr getPacketTarget(const char* buffer, int towards){
			NodeAddr tempAddr;
			tempAddr.serial_id = towards==DUMP_PROTOCOL_PACKET_IN ? *((long long*)(buffer+6)) : *((long long*)(buffer+8));
			return tempAddr;
		}

		static void setPacketQueryValueType(char* buffer, int type){
			buffer[16] = (char)type;
		}

		static int getPacketQueryValueType(const char* buffer, int towards){
			return towards==DUMP_PROTOCOL_PACKET_IN ? buffer[14]:buffer[16];
		}

		static void setPacketQueryValueLen(char* buffer, int len){
			buffer[17] = (char)len;
		}

		static int getPacketQueryValueLen(const char* buffer, int towards){
			return towards==DUMP_PROTOCOL_PACKET_IN ? buffer[15]:buffer[17];
		}

		static void setPacketQueryValue(char* buffer, const char* value, int valuelen){
			memcpy(buffer+18, value, valuelen);
		}

		static int getPacketQueryValue(const char* buffer, char* value, int valueLen, int towards){
			int len = getPacketQueryValueLen(buffer, towards);
			towards==DUMP_PROTOCOL_PACKET_IN ? memcpy(value, buffer+16, len): memcpy(value, buffer+18, len);
			return len;
		}

		//only for in packet
		static int getPacketQueryResult(const char* buffer){
			int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
			return buffer[QueryValueLen+16];
		}

		static int getPacketDeviceInfoNickLen(const char* buffer){
			int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
			return buffer[QueryValueLen+18];
		}

		static int getPacketDeviceInfoNick(const char* buffer, char* nick, int len){
			int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
			int nickValueLen =  getPacketDeviceInfoNickLen(buffer);
			memcpy(buffer+19+QueryValueLen, nick, nickValueLen);
			return nickValueLen;
		}

		// the same as result
		static int getPacketDeviceInfoShowMe(const char* buffer){
			int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
			return buffer[QueryValueLen+17];
		}

		static int getPacketDeviceInfoDeviceIdLen(const char* buffer){
			int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
			int nickValueLen =  getPacketDeviceInfoNickLen(buffer);
			return buffer[19 + QueryValueLen + nickValueLen];
		}

		static int getPacketDeviceInfoDeviceId(const char* buffer, char* deviceId, int length){
			int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
			int nickValueLen =  getPacketDeviceInfoNickLen(buffer);
			int deviceIdLen = getPacketDeviceInfoDeviceIdLen(buffer);
			memcpy(deviceId, buffer+20+QueryValueLen+nickValueLen, deviceIdLen);
			return deviceIdLen;
		}

		static int getPacketDeviceInfoDeviceIMEI(const char* buffer, char* imei, int length){
			int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
			int nickValueLen =  getPacketDeviceInfoNickLen(buffer);
			int deviceIdLen = getPacketDeviceInfoDeviceIdLen(buffer);
			memcpy(imei, buffer+20+QueryValueLen+nickValueLen+deviceIdLen, 16);
			return 16;
		}

		static int getPacketDeviceInfoTTL(const char* buffer){
			int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
			int nickValueLen =  getPacketDeviceInfoNickLen(buffer);
			int deviceIdLen = getPacketDeviceInfoDeviceIdLen(buffer);
			return buffer[36+QueryValueLen+nickValueLen+deviceIdLen];
		}

		static void dumpPacket(const char* buffer, int towards, const char* fileName){
			FILE* dumpFile = fopen(fileName, "w+");
			char timer[256]={0};
			if(dumpFile == NULL){
				return;
			}   
			TransContentSetting::getTimeStr(timer, 256);
			fprintf(dumpFile, "\t\t\t\tdump function call query target protocol\n");
			fprintf(dumpFile, "\ttime stamp: %s\n", timer);

			if(towards==DUMP_PROTOCOL_PACKET_OUT){
				fprintf(dumpFile, "\tpacket length: %d\n", getPacketLength(buffer));
			}
			fprintf(dumpFile, "\tpacket main code: %d\n", getPacketMainMessage(buffer, towards));
			fprintf(dumpFile, "\tpacket sub code: %d\n", getPacketSubMessageCode(buffer, towards));
			fprintf(dumpFile, "\tpacket localPort: %d\n", getPacketLocalPort(buffer, towards));
			fprintf(dumpFile, "\tpacket target addr: %lld\n", getPacketTarget(buffer, towards).serialId);
			fprintf(dumpFile, "\tpacket query type: %d\n", getPacketQueryValueType(buffer, towards));
			fprintf(dumpFile, "\tpacket query value len: %d\n", getPacketQueryValueLen(buffer, towards));
			memset(timer, 0x00, 256);
			fprintf(dumpFile, "\tpacket query value: %s\n", getPacketQueryValue(buffer, timer, 256, towards));
			if(towards==DUMP_PROTOCOL_PACKET_IN){
				fprintf(dumpFile, "\tpacket query result: %d\n", getPacketQueryResult(buffer));
				fprintf(dumpFile, "\tpacket query response: showMe: %d\n", getPacketDeviceInfoShowMe(buffer));
				fprintf(dumpFile, "\tpacket query response: nickLen: %d\n", getPacketDeviceInfoNickLen(buffer));
				memset(timer, 0x00, 256);
				fprintf(dumpFile, "\tpacket query response: nick: %s\n", getPacketDeviceInfoNick(buffer, timer, 256));
				fprintf(dumpFile, "\tpacket query response: deviceId length: %d\n", getPacketDeviceInfoDeviceIdLen(buffer));
				memset(timer, 0x00, 256);
				fprintf(dumpFile, "\tpacket query response: deviceId value: %s\n", getPacketDeviceInfoDeviceId(buffer, timer, 256));
				memset(timer, 0x00, 256);
				fprintf(dumpFile, "\tpacket query response: IMEI: %s\n", getPacketDeviceInfoDeviceIMEI(buffer, timer, 256));
				fprintf(dumpFile, "\tpacket query response: TTL: %d\n", getPacketDeviceInfoTTL(buffer));
			}
		}
};
#endif //TRANSFORMERCONTENTQUERYTARGET_HPP_3
